/*
   Splash Screen Plugin for Miranda-IM (www.miranda-im.org)
   (c) 2004-2007 nullbie, (c) 2005-2007 Thief

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

   File name      : $URL: http://svn.mirandaim.ru/mainrepo/splashscreen/trunk/src/splash.cpp $
   Revision       : $Rev: 579 $
   Last change on : $Date: 2007-03-15 02:16:13 +0300 (Thu, 15 Mar 2007) $
   Last change by : $Author: Thief $

*/

#include "headers.h"
#include "splash.h"

bool ShowSplash(bool bpreview)
{      
   if (bpreview && bpreviewruns) return 0;

   if (bpreview) bpreviewruns = true;
   unsigned short timeout = 0;

   SplashBmp = new MyBitmap;

   #ifdef _DEBUG
      logMessage("Loading splash file", szSplashFile);
   #endif

   SplashBmp->loadFromFile(szSplashFile, NULL);

   DWORD threadID;
     
   #ifdef _DEBUG
     logMessage("Thread","start");
   #endif

   if (bpreview)
   {
      ShowWindow(hwndSplash, SW_HIDE);
      DestroyWindow(hwndSplash);

	  timeout = 2000;
      #ifdef _DEBUG
         logMessage("Preview","yes");
      #endif
   }
   else
   {  
       timeout = options.showtime;   
       #ifdef _DEBUG
         char b [40];
         sprintf(b,"%d",options.showtime);
         logMessage("Timeout",b);
       #endif
   }

   hSplashTread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SplashThread, (LPVOID)timeout, 0, &threadID);

   #ifdef _DEBUG
     logMessage("Thread","end");
   #endif

   CloseHandle(hSplashTread);

   return 1;
}
LRESULT CALLBACK SplashWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
   switch (message)
   {
       case WM_LOADED:
       {
		   #ifdef _DEBUG
               logMessage("WM_LOADED","called");
		   #endif

           if (!MyUpdateLayeredWindow) ShowWindow(hwndSplash, SW_SHOWNORMAL);
		   if (!options.showtime) SetTimer(hwnd, 7, 2000, 0);
		  
           break;
       }
   
   case WM_LBUTTONDOWN:
	   PostMessage(hwnd, WM_CLOSE, 0, 0);
	   break;

   case WM_TIMER:

	  #ifdef _DEBUG
		char b [40];
		sprintf(b,"%d",wParam);
		logMessage("Timer ID",b);
		sprintf(b,"%d",options.showtime);
		logMessage("ShowTime value",b);
      #endif

	  if (options.showtime > 0) //TimeToShow enabled
	  {
		  if (wParam == 6)
		  {
			PostMessage(hwnd, WM_CLOSE, 0, 0);
			#ifdef _DEBUG
				logMessage("Showtime timer","triggered");
			#endif
		  }
	  }
	  else
	  {
		PostMessage(hwnd, WM_CLOSE, 0, 0);
		if (wParam == 7)
		{
			#ifdef _DEBUG
				logMessage("On Modules Loaded timer","triggered");
			#endif
		}
		if (wParam == 8)
		{
			#ifdef _DEBUG
				logMessage("On Modules Loaded workaround","triggered");
			#endif
		}
	  }

      break;
   
   case WM_RBUTTONDOWN:
   {
     ShowWindow(hwndSplash, SW_HIDE);
     DestroyWindow(hwndSplash);
	 
     break;
   }

   case WM_CLOSE:
   {
     if (MyUpdateLayeredWindow) // Win 2000+
     {
        RECT rc; GetWindowRect(hwndSplash, &rc);
        POINT ptDst = { rc.left, rc.top };
        POINT ptSrc = { 0, 0 };
        SIZE sz = { rc.right - rc.left, rc.bottom - rc.top };

        BLENDFUNCTION blend;
        blend.BlendOp =             AC_SRC_OVER;
        blend.BlendFlags =          0;
        blend.SourceConstantAlpha = 255;
        blend.AlphaFormat =         AC_SRC_ALPHA;

        // Fade Out
       if (options.fadeout)
	   {
          int i;
          for (i = 255; i>=0; i -= options.fosteps)
          {
            blend.SourceConstantAlpha = i;
            MyUpdateLayeredWindow(hwndSplash, NULL, &ptDst, &sz, SplashBmp->getDC(), &ptSrc, 0xffffffff, &blend, LWA_ALPHA);
            Sleep(1);
          }
       }
     }
       if (bserviceinvoked) bserviceinvoked = false;
	   if (bpreviewruns) bpreviewruns = false;
	  		
	   DestroyWindow(hwndSplash);
   }

   case WM_MOUSEMOVE:
   {
      if (bserviceinvoked)
      {
         PostMessage(hwnd, WM_CLOSE, 0, 0);
      }
      break;
   }

   case WM_DESTROY:
   {
	   PostQuitMessage(0);
	   #ifdef _DEBUG
           logMessage("WM_DESTROY","called");
       #endif
	   break;
   }

   case WM_PAINT:
   {
      if (!MyUpdateLayeredWindow) // Win 9x
      {   
         #ifdef _DEBUG
           logMessage("WM_PAINT","painting..");
         #endif
         PAINTSTRUCT ps;
         BeginPaint(hwndSplash, &ps);
         BitBlt(ps.hdc, 0, 0, SplashBmp->getWidth(), SplashBmp->getHeight(), tmpBmp->getDC(), 0, 0, SRCCOPY);
         EndPaint(hwndSplash, &ps);   
      }
      break;
   }
      
      ShowWindow(hwndSplash, SW_HIDE);
      DestroyWindow(hwndSplash);
      break;
   }

   return DefWindowProc(hwnd, message, wParam, lParam);
}

int SplashThread(void *arg)
{
   // Old code, doesn't support mp3 files
   if (options.playsnd) PlaySound(szSoundFile, NULL, SND_ASYNC | SND_FILENAME | SND_NOWAIT);
	
   /*
   // Buggy code, dropped for now
   if (options.playsnd) 
   {
		char cmd[32] = "play";
		
		// TODO: figure out if this is working.
		if(options.loopsnd) strcat(cmd, " repeat");

		#ifdef _DEBUG
		logMessage("Command",cmd);
        #endif
			
		if(strlen(szSoundFile) && (mciWnd = MCIWndCreate(NULL, 0, MCIWNDF_NOPLAYBAR, szSoundFile)) != NULL)
		{
			SetWindowPos(mciWnd,HWND_BOTTOM,-1000,-1000,0,0,SWP_NOSIZE);
			ShowWindow(mciWnd, SW_HIDE);
			if(MCIWndCanPlay(mciWnd))
				MCIWndSendString(mciWnd, cmd);
		}
   }
   */

   WNDCLASSEX wcl;
   wcl.cbSize = sizeof(wcl);
   wcl.lpfnWndProc = SplashWindowProc;
   wcl.style = 0;
   wcl.cbClsExtra = 0;
   wcl.cbWndExtra = 0;
   wcl.hInstance = hInst;
   wcl.hIcon = NULL;
   wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
   wcl.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
   wcl.lpszMenuName = NULL;
   wcl.lpszClassName = SPLASH_CLASS;
   wcl.hIconSm = NULL;
   RegisterClassEx(&wcl);

   RECT DesktopRect;
   int w = GetSystemMetrics(SM_CXSCREEN);
   int h = GetSystemMetrics(SM_CYSCREEN);
   DesktopRect.left = 0;
   DesktopRect.top = 0;
   DesktopRect.right = w;
   DesktopRect.bottom = h;

   RECT WindowRect;
   WindowRect.left = (DesktopRect.left + DesktopRect.right - SplashBmp->getWidth()) / 2;
   WindowRect.top  = (DesktopRect.top + DesktopRect.bottom - SplashBmp->getHeight()) / 2;
   WindowRect.right = WindowRect.left + SplashBmp->getWidth();
   WindowRect.bottom = WindowRect.top + SplashBmp->getHeight();

   hwndSplash = CreateWindowEx(
      WS_EX_TOOLWINDOW | WS_EX_TOPMOST,//dwStyleEx
      "MirandaSplash", //Class name
      NULL, //Title
      DS_SETFONT | DS_FIXEDSYS | WS_POPUP, //dwStyle
      WindowRect.left, // x
      WindowRect.top, // y
      SplashBmp->getWidth(), // Width
      SplashBmp->getHeight(), // Height
      HWND_DESKTOP, //Parent
      NULL, //menu handle
      hInst, //Instance
      NULL);

   RECT rc; GetWindowRect(hwndSplash, &rc);
   POINT ptDst = {rc.left, rc.top};
   POINT ptSrc = {0, 0};
   SIZE sz = {rc.right - rc.left, rc.bottom - rc.top};
   bool splashWithMarkers = false;

   BLENDFUNCTION blend;
   blend.BlendOp =             AC_SRC_OVER;
   blend.BlendFlags =          0;
   blend.SourceConstantAlpha = 0;
   blend.AlphaFormat =         AC_SRC_ALPHA;

   if (options.showversion)
   {
     // locate text markers:
	 int i, x = -1, y = -1;

	 int splashWidth = SplashBmp->getWidth();
	 for (i = 0; i < splashWidth; ++i)
		 if (SplashBmp->getRow(0)[i] & 0xFF000000)
		 {
			 if (x < 0)
			 {
				 x = i-1; // 1 pixel for marker line
				 splashWithMarkers = true;
			 } else
			 {
                 x = -1;
				 splashWithMarkers = false;
				 break;
			 }
		 }
	 int splashHeight = SplashBmp->getHeight();
	 for (i = 0; splashWithMarkers && (i < splashHeight); ++i)
		 if (SplashBmp->getRow(i)[0] & 0xFF000000)
		 {
			 if (y < 0)
			 {
				 y = i-1; // 1 pixel for marker line
				 splashWithMarkers = true;
			 } else
			 {
                 y = -1;
				 splashWithMarkers = false;
				 break;
			 }
		 }

	 char verString[256] = {0};
	 //char* ptr_verString = &verString;
	 if (strlen(szPrefix)) strcat(verString,(char*)szPrefix);
	 strcat(verString,mirandaVerString);
	 LOGFONT lf = {0};
	 lf.lfHeight = 14;
	 strcpy(lf.lfFaceName, "Verdana");
	 SelectObject(SplashBmp->getDC(), CreateFontIndirect(&lf));
	 if (!splashWithMarkers)
	 {
		SIZE v_sz = {0,0};
		GetTextExtentPoint32(SplashBmp->getDC(),verString,strlen(verString),&v_sz);
		x = SplashBmp->getWidth()/2-(v_sz.cx/2);
		y = SplashBmp->getHeight()-(SplashBmp->getHeight()*(100-90)/100);
	 }
	 //SplashBmp->DrawText(verString,SplashBmp->getWidth()/2-(v_sz.cx/2),SplashBmp->getHeight()-30);	 
	 SetBkMode(SplashBmp->getDC(), TRANSPARENT);
	 SplashBmp->DrawText(verString,x,y);
	 //free (ptr_verString);
   }

   if (MyUpdateLayeredWindow) // Win 2000+
   {
      SetWindowLong(hwndSplash, GWL_EXSTYLE, GetWindowLong(hwndSplash, GWL_EXSTYLE) | WS_EX_LAYERED);
/*
	  if (splashWithMarkers)
	  {
		  ++ptSrc.x;
		  ++ptSrc.y;
	  }
*/
      MyUpdateLayeredWindow(hwndSplash, NULL, &ptDst, &sz, SplashBmp->getDC(), &ptSrc, 0xffffffff, &blend, LWA_ALPHA);

      ShowWindow(hwndSplash, SW_SHOWNORMAL);
   }
   else // Win 9x
   {   
      tmpBmp = new MyBitmap(SplashBmp->getWidth(),SplashBmp->getHeight());
      HDC dtDC = GetDC(GetDesktopWindow());
     
      BitBlt(tmpBmp->getDC(),
               0,
               0,
               SplashBmp->getWidth(),
               SplashBmp->getHeight(),
               dtDC,
               (DesktopRect.left + DesktopRect.right - SplashBmp->getWidth()) / 2,
               (DesktopRect.top + DesktopRect.bottom - SplashBmp->getHeight()) / 2,
               SRCCOPY);

      ReleaseDC(GetDesktopWindow(), dtDC);

      tmpBmp->Blend(SplashBmp, (splashWithMarkers?-1:0), (splashWithMarkers?-1:0), SplashBmp->getWidth(), SplashBmp->getHeight());   

   }

   if (MyUpdateLayeredWindow) // Win 2000+
   {
      if (options.fadein)
	  {
          // Fade in
		  int i;
          for (i = 0; i < 255; i += options.fisteps)
          {
               blend.SourceConstantAlpha = i;
               MyUpdateLayeredWindow(hwndSplash, NULL, &ptDst, &sz, SplashBmp->getDC(), &ptSrc, 0xffffffff, &blend, LWA_ALPHA);
               Sleep(1);
          }      
      }
      blend.SourceConstantAlpha = 255;
      MyUpdateLayeredWindow(hwndSplash, NULL, &ptDst, &sz, SplashBmp->getDC(), &ptSrc, 0xffffffff, &blend, LWA_ALPHA);
   }

   if (DWORD(arg) > 0)
   {
	   if (SetTimer(hwndSplash, 6, DWORD(arg), 0))
	   {
	     #ifdef _DEBUG
		   logMessage("Timer TimeToShow","set");
         #endif
	   }
   }
   else
   if (bmodulesloaded)
   {
	   if (SetTimer(hwndSplash, 8, 2000, 0))
	   {
	     #ifdef _DEBUG
		   logMessage("Timer Modules loaded","set");
         #endif
	   }
   }

   // The Message Pump
   MSG msg;
   while (GetMessage(&msg, NULL, 0, 0) == TRUE) //NULL means every window in the thread; == TRUE means a safe pump.
   { 
      TranslateMessage(&msg);
      DispatchMessage(&msg);
   }

   ExitThread(0);
   return 1;
}
